/************************************************************************
                        WingedEdges.h - Copyright Claudio Botta

This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Boston, MA 02110, USA

This file was generated on Tue May 6 2008 at 09:58:07
The original location of this file is geomagick/WingedEdges.h
**************************************************************************/


#ifndef WINGED_EDGES_H
#define WINGED_EDGES_H
#include "MeshType.h"

#include <vector>
#include <string>
#include <boost/foreach.hpp>

namespace geomagick{


/**
*	class WEVertex
*/
class WEVertex
{
public:
        int IncidentEdge;
        Vector3d Coordinates;
};

/**
 * class WEdge
*/
class WEdge
{
public:
	WEdge(){
		StartVertex = -1;
		EndVertex = -1;
		LeftFace = -1;
		RightFace = -1;
		Left_pred = -1;
		Left_succ = -1;
		Right_pred = -1;
		Right_succ = -1;
	}
        int StartVertex;
        int EndVertex;
        int LeftFace;
        int RightFace;
        int Left_pred;
        int Left_succ;
        int Right_pred;
        int Right_succ;
        // !TODO EXTEND ME!
};



/**
  * class WingedEdges impllements a Winge-Edge Data Sructure
  * as described on http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/model/winged-e.html
 **/
class WingedEdges : public MeshType
{
public:
	WingedEdges()
	{
		Vertices = boost::shared_ptr<vector<WEVertex*> >( new vector<WEVertex*>() );
		Edges =  boost::shared_ptr<vector<WEdge*> >(new vector<WEdge*>());
		Faces = boost::shared_ptr<vector<int> >(new vector<int>());
	}

private:

        // Static Private attributes
        //

        // Private attributes
        boost::shared_ptr<vector<WEVertex*> > Vertices;
        boost::shared_ptr<vector<int> > Faces;
        boost::shared_ptr<vector<WEdge*> > Edges;



public:


        // Private attribute accessor methods
        //

private:

public:
        /**
        * 	Adds an Edge to the Winged-Edges data structure
        * 	It will automatically create proper WEdge-Instances.
        *	The use of addEddEdgeFromTo(int pred,
        *				    int from,
        *				    int to,
        *				    int succ,
        *				    int Face)
        *	is recommended rather than this function.
        *
        *	@param from the index of the starting Vertex of the Edge
        * 	@param to   the index of the ending Vertex of the Edge
        *	@param Face the polygon to which the Edge belongs
        *
        **/
        int addEdgeFromTo(int from, int to, int Face) {
                int index;
                WEdge* EdgePtr =  getWedge(from,to, index);
                if (EdgePtr == NULL) {
                        EdgePtr = new WEdge();
                        EdgePtr->StartVertex = from;
                        EdgePtr->EndVertex = to;
                        EdgePtr->LeftFace = Face;
                } else {
                        if (EdgePtr->StartVertex == from) {
                                EdgePtr->LeftFace = Face;
                        } else {
                                EdgePtr->RightFace = Face;
                        }
                }
                // Decide wheter the  Face is on the left or on the right side


                return index;
        }

        /**
        * 	Adds an Edge to the Winged-Edges data structure
        * 	It will automatically create proper WEdge-Instances.
        *
        *	@param pred the index of the predecessor Vertex
        *	@param from the index of the starting Vertex of the Edge
        * 	@param to   the index of the ending Vertex of the Edge
        *	@param succ the index of the successor Vertex of the Edge
        *	@param Face the polygon to which the Edge belongs
        *
        **/
        int addEdgeFromTo(int pred, int from, int to,int succ, int Face) {
                int index = -1;
                int predEdgeIndex;
                int succEdgeIndex;
		bool new_pred = false;
		bool new_succ = false;

                WEdge* EdgePtr =  getWedge(from,to, index);
                WEdge* predEdgePtr = getWedge(pred,from, predEdgeIndex);
                if (predEdgePtr == NULL) {
			new_pred = true;
                        predEdgePtr = new WEdge();
                        predEdgePtr->StartVertex = pred;
                        predEdgePtr->EndVertex = from;
                        predEdgePtr->LeftFace = Face;
			if(index != -1)
			predEdgePtr->Left_succ = index;
                        this->Edges->push_back(predEdgePtr);
                        predEdgeIndex = this->Edges->size()-1;

                }
		if(predEdgePtr->LeftFace == -1 && predEdgePtr->RightFace != Face)
		{
			predEdgePtr->LeftFace = Face;
		}
		else{
			if(predEdgePtr->RightFace ==-1 && predEdgePtr->LeftFace != Face){
			predEdgePtr->RightFace = Face;
			}

		}
		
                WEdge* succEdgePtr = getWedge(to,succ, succEdgeIndex);
                if (succEdgePtr == NULL) {
			new_succ = true;
                        succEdgePtr = new WEdge();
                        succEdgePtr->StartVertex = to;
                        succEdgePtr->EndVertex =  succ;
                        succEdgePtr->LeftFace = Face;
                        this->Edges->push_back(succEdgePtr);
                        succEdgeIndex = this->Edges->size()-1;

                }

		if(succEdgePtr->LeftFace == -1 && succEdgePtr->RightFace != Face)
		{
			succEdgePtr->LeftFace = Face;
		}
		else{
			if(succEdgePtr->RightFace ==-1 && succEdgePtr->LeftFace != Face){
			succEdgePtr->RightFace = Face;
			}

		}

                if (EdgePtr == NULL) {
                        EdgePtr = new WEdge();
                        EdgePtr->StartVertex = from;
                        EdgePtr->EndVertex = to;
                        EdgePtr->LeftFace = Face;
			EdgePtr->Left_pred = predEdgeIndex;
			EdgePtr->Left_succ = succEdgeIndex;
	
                        this->Edges->push_back(EdgePtr);
                        index = this->Edges->size()-1;
			if(predEdgePtr->LeftFace == Face)predEdgePtr->Left_succ = index;
			if(predEdgePtr->RightFace == Face)predEdgePtr->Right_succ = index;
			if(succEdgePtr->LeftFace == Face)succEdgePtr->Left_pred = index;
			if(succEdgePtr->RightFace == Face)succEdgePtr->Right_pred = index;
			#if DEBUG
			cout << "Edge: " << index << ";" << "succEdgeIndex" << succEdgeIndex << endl;
			#endif
                } else {
                        if (EdgePtr->StartVertex == from) {
                                EdgePtr->LeftFace = Face;
                                EdgePtr->Left_pred = predEdgeIndex;
                                EdgePtr->Left_succ = succEdgeIndex;
				if(predEdgePtr->LeftFace == Face)predEdgePtr->Left_succ = index;
				if(predEdgePtr->RightFace == Face)predEdgePtr->Right_succ = index;
				if(succEdgePtr->LeftFace == Face)succEdgePtr->Left_pred = index;
				if(succEdgePtr->RightFace == Face)succEdgePtr->Right_pred = index;
                        } else {
                                EdgePtr->RightFace = Face;
                                EdgePtr->Right_pred = predEdgeIndex;
                                EdgePtr->Right_succ = succEdgeIndex;
				if(predEdgePtr->LeftFace == Face)predEdgePtr->Left_succ = index;
				if(predEdgePtr->RightFace == Face)predEdgePtr->Right_succ = index;
				if(succEdgePtr->LeftFace == Face)succEdgePtr->Left_pred = index;
				if(succEdgePtr->RightFace == Face)succEdgePtr->Right_pred = index;
                        }
                }



                return index;
        }




        /**
        *	@return a Pointer to the WEdge structure which
        * 	Interconnects VertexA and VertexB. If no such WEdgw
        *	structure exists a NULL pointer is returned.
        *	@param VertexA a Vertex to which the WEdge is connected.
        *	@param VertexB a Vertex to which the WEdge is connected.
        *
        **/
        WEdge* getWedge(int VertexA, int VertexB) {
                foreach(WEdge* currentWEdge, *Edges) {
                        if (currentWEdge->StartVertex == VertexA && currentWEdge->EndVertex == VertexB) {
                                return currentWEdge;
                        }
                        if (currentWEdge->StartVertex == VertexB && currentWEdge->EndVertex == VertexA) {
                                return currentWEdge;
                        }
                }
                return NULL;

        }
        /**
        *	@return a Pointer to the WEdge structure which
        * 	Interconnects VertexA and VertexB. If no such WEdgw
        *	structure exists a NULL pointer is returned.
        *	@param VertexA a Vertex to which the WEdge is connected.
        *	@param VertexB a Vertex to which the WEdge is connected.
        *	@param index a reference to the index of the WEdge.
        *
        **/
        WEdge* getWedge(int VertexA, int VertexB, int& index) {
                int i = 0;
                foreach(WEdge* currentWEdge, *Edges) {
                        if (currentWEdge->StartVertex == VertexA && currentWEdge->EndVertex == VertexB) {
                                index = i;
                                return currentWEdge;
                        }
                        if (currentWEdge->StartVertex == VertexB && currentWEdge->EndVertex == VertexA) {
                                index = i;
                                return currentWEdge;
                        }
                        i++;
                }

                return NULL;
        }

	boost::shared_ptr<vector<WEVertex*> > getVertices(){
		return this->Vertices;
	}

        void setWEdges(vector<WEdge*>* newWEdges) {
                Edges =  boost::shared_ptr<vector<WEdge*> >(newWEdges);
        }

        void addEdge(WEdge* newWEdge) {
                Edges->push_back(newWEdge);
        }
	
	WEdge* getEdgeAt(int i) {
		return this->Edges->at(i);
	}
	int getEdgeFrom(int Vertex) {

	int index = 0;
		foreach(WEdge* currentWEdge, *Edges) {
                        if (currentWEdge->StartVertex == Vertex || currentWEdge->EndVertex == Vertex) {
                                return index;
                        }
			index++;
		}
		return -1;
	}
        void addFace(int IncidentEdge) {
                this->Faces->push_back(IncidentEdge);
        }

	boost::shared_ptr<vector<int> > getFaces(){
		return (this->Faces);
	}

        void addVertex(WEVertex& newWEVertex) {
                Vertices->push_back(&newWEVertex);
        }

        void addVertexCoordinates(Vector3d& VertexCoordinates) {
		WEVertex* mVertex = new WEVertex();
		mVertex->Coordinates.x = VertexCoordinates.x;
		mVertex->Coordinates.y = VertexCoordinates.y;
		mVertex->Coordinates.z = VertexCoordinates.z;
		Vertices->push_back((mVertex));
        }
	
	/**
	*	Set the incident Edge of the Vertex with the index 
	*	VertexNumber.
	*	@param VertexNumber the index of the Vertex in this->Vertices.
	*	@param incidentEdgeNumber the index of the incident Edge in this->Edges.
	**/
	void VertexSetIncidentEdge(int VertexNumber,int incidentEdgeNumber ){
		Vertices->at(VertexNumber)->IncidentEdge = incidentEdgeNumber;
	}


        virtual void printName() {
                cout << "Winged_Edges\n";
        }
        static  BaseType* init() {
                return new WingedEdges;
        }
        static string getTypeName() {
                return "Winged_Edges";
        }
        static BaseTypeId* getTypeId() {
                BaseTypeId* newBaseTypeId = new BaseTypeId;
                newBaseTypeId->getTypeName = WingedEdges::getTypeName;
                newBaseTypeId->init = WingedEdges::init;
                return newBaseTypeId;
        }

        void printStatistic() {
                // !TODO Implement me!
                //cout << "Number of Triangles: " << this->TriangleList.size() << endl;
                //cout << "Number of Vertices: " << this->VertexCoordinates.size() << endl;
        }

	void printWingedEdges(){
		
		int i = 0;
		foreach(WEdge * curWEdge, *(this->Edges) )
		{
		cout << "WEDGE " << i << endl;
		cout << "from:" << curWEdge->StartVertex << "," << "to:" << curWEdge->EndVertex << endl;
		cout << "LeftFace:" << curWEdge->LeftFace << endl; 
		cout << "RightFace:" << curWEdge->RightFace << endl;
		cout << "Left_pred:" << curWEdge->Left_pred << endl;
		cout << "Right_pred:" << curWEdge->Right_pred << endl;;
		cout << "Left_succ:" << curWEdge->Left_succ << endl;
		cout << "Right_succ:" << curWEdge->Right_succ << endl;
		cout << endl;
		i++;
		}
	
	}
private:



};
}

#endif // WINGED_EDGES_H
